package xyz.riceball.usercore.service.impl;

import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import xyz.riceball.framework.core.bean.ApiR;
import xyz.riceball.framework.core.bean.ApiRc;
import xyz.riceball.framework.core.context.UserContext;
import xyz.riceball.framework.core.exception.RiceBallBizErrorException;
import xyz.riceball.framework.core.exception.RiceBallBizWarnException;
import xyz.riceball.framework.core.util.BeanUtils;
import xyz.riceball.framework.core.util.MessageUtils;
import xyz.riceball.framework.core.util.TransactionUtils;
import xyz.riceball.usercore.entity.dto.RoleRightTreeDTO;
import xyz.riceball.usercore.entity.po.*;
import xyz.riceball.usercore.mapper.*;
import xyz.riceball.usercore.service.RoleRightService;
import xyz.riceball.usercore.service.RoleService;
import xyz.riceball.usercore.service.RouteService;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 角色表(Role)表服务实现类
 *
 * @author xiaovcloud
 * @since 2022-04-24 20:17:49
 */
@Slf4j
@Service("roleService")
public class RoleServiceImpl extends ServiceImpl<RoleMapper, RolePO> implements RoleService {

    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private RoleRightMapper roleRightMapper;
    @Resource
    private RoleRightService roleRightService;
    @Resource
    private RouteMapper routeMapper;
    @Resource
    private MenuMapper menuMapper;
    @Resource
    private RouteService routeService;

    @Override
    public List<RolePO> selectRoleByUserId(String userId) {
        return getBaseMapper().selectRoleByUserId(userId);
    }

//    @Override
//    public List<RolePO> selectRoleByMenuId(String menuId) {
//        return getBaseMapper().selectRoleByMenuId(menuId);
//    }

    @Override
    public List<RolePO> selectRoleByRouteId(String routeId) {
        return getBaseMapper().selectRoleByRouteId(routeId);
    }

    @Override
    public ApiR<RolePO> add(RolePO rolePO) {
        checkRoleBeforeDb(rolePO);
        BeanUtils.buildAutoField(rolePO, true, UserContext.getUserId());
        int insert = getBaseMapper().insert(rolePO);
        return ApiR.msgData(insert == 1, "新增角色成功！", "新增角色失败！", rolePO);
    }

    /**
     * 角色操作检测
     *
     * @param rolePO
     */
    private void checkRoleBeforeDb(RolePO rolePO) {
        List<RolePO> roleList;
        if (StrUtil.isEmpty(rolePO.getId())) {
            //新增角色检测，主要检测code和name
            LambdaQueryWrapper<RolePO> wrapperCode = Wrappers.<RolePO>lambdaQuery();
            wrapperCode.eq(RolePO::getCode, rolePO.getCode());
            roleList = getBaseMapper().selectList(wrapperCode);
            if (roleList.size() > 0) {
                throw new RiceBallBizWarnException("角色编码重复：{}", rolePO.getCode());
            }
            LambdaQueryWrapper<RolePO> wrapperName = Wrappers.<RolePO>lambdaQuery();
            wrapperName.eq(RolePO::getName, rolePO.getName());
            roleList = getBaseMapper().selectList(wrapperName);
            if (roleList.size() > 0) {
                throw new RiceBallBizWarnException("角色名称重复：{}", rolePO.getName());
            }
        } else {
            //修改角色检测，code无法修改，这里主要检测名字
            LambdaQueryWrapper<RolePO> wrapperName = Wrappers.<RolePO>lambdaQuery();
            wrapperName.eq(RolePO::getName, rolePO.getName());
            roleList = getBaseMapper().selectList(wrapperName);
            if (roleList.size() > 1) {
                throw new RiceBallBizWarnException("角色名称重复：{}", rolePO.getName());
            }
            if (roleList.size() == 1) {
                if (!roleList.get(0).getId().equals(rolePO.getId())) {
                    throw new RiceBallBizWarnException("角色名称重复：{}", rolePO.getName());
                }
            }
        }
    }

    @Override
    public boolean edit(RolePO rolePO) {
        checkRoleBeforeDb(rolePO);
        RolePO role = getBaseMapper().selectById(rolePO.getId());
        BeanUtils.copyWithoutNull(role, rolePO);
        BeanUtils.buildAutoField(role, true, UserContext.getUserId());
        int edit = getBaseMapper().updateById(role);
        return edit == 1;
    }

    @Override
    public ApiR<Void> delete(List<String> ids) {
        ApiRc<Void> del = ApiRc.buildResultCount(ids.size());

        for (String id : ids) {
            try {
                RolePO rolePO = getBaseMapper().selectById(id);
                if (rolePO==null){
                    del.append(MessageUtils.format("不存在id为{}的数据<br/>",id));
                    continue;
                }

                //1。删除用户角色关联
                LambdaQueryWrapper<UserRolePO> wrapperUser = Wrappers.<UserRolePO>lambdaQuery();
                wrapperUser.eq(UserRolePO::getRoleId, id);

                //2。角色权限
                LambdaQueryWrapper<RoleRightPO> wrapperRight = Wrappers.lambdaQuery();
                wrapperUser.eq(UserRolePO::getRoleId, id);

                TransactionUtils.doInTransactionWithRequired(() -> {
                    roleRightMapper.delete(wrapperRight);
                    userRoleMapper.delete(wrapperUser);
                    //3。删除角色
                    getBaseMapper().deleteById(id);
                    return Void.class;
                });

                del.success();
            } catch (Exception e) {
                log.error("删除角色失败，id：{}", id,e);
                del.append(MessageUtils.format("id为{}角色删除失败:{}<br/>", id,e.getMessage()));
            }
        }
        return ApiRc.getResult(del);
    }

    @Override
    public boolean putRight(String roleId, List<String> routeIds) {
        //检测数据正确性
        isCanPutRight(roleId, routeIds);

        Iterator<String> iterator = routeIds.iterator();
        while (iterator.hasNext()){
            String routeId = iterator.next();
            RoutePO routePO = routeMapper.selectById(routeId);
            if (routePO == null) {
                iterator.remove();
            }
        }

        //需要新增的
        List<RoleRightPO> needAddRoleRight = new ArrayList<>();
        routeIds.forEach(routeId -> {
            RoleRightPO roleRightPO = new RoleRightPO();
            roleRightPO.setRoleId(roleId);
            roleRightPO.setRouteId(routeId);
            needAddRoleRight.add(roleRightPO);
        });
        LambdaQueryWrapper<RoleRightPO> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(RoleRightPO::getRoleId, roleId);

        return TransactionUtils.doInTransactionWithRequired(() -> {
            boolean delete = roleRightService.remove(wrapper);
            boolean add = roleRightService.saveBatch(needAddRoleRight);
            return delete && add;
        });
    }

    /**
     * 判断入参是否正确
     * @param roleId
     * @param routeIds
     */
    private void isCanPutRight(String roleId, List<String> routeIds) {
        RolePO rolePO = getBaseMapper().selectById(roleId);
        if (rolePO == null) {
            log.error("roleId找不到角色：{}", roleId);
            throw new RiceBallBizErrorException("入参错误！");
        }
    }

    @Override
    public Page<RolePO> selectPage(Page<RolePO> page, RolePO rolePO) {
        LambdaQueryWrapper<RolePO> wrapper = Wrappers.lambdaQuery();
        if (StrUtil.isNotEmpty(rolePO.getCode())) {
            wrapper.eq(RolePO::getCode, rolePO.getCode());
        }
        if (StrUtil.isNotEmpty(rolePO.getName())) {
            wrapper.like(RolePO::getName, rolePO.getName());
        }
        if (ObjectUtil.isNotEmpty(rolePO.getStatus())) {
            wrapper.eq(RolePO::getStatus, rolePO.getStatus());
        }
        return getBaseMapper().selectPage(page, wrapper);
    }

    @Override
    public RoleRightTreeDTO getRight(String roleId) {
        List<Tree<String>> tree = routeService.tree();
        List<RoutePO> routePOList = roleRightMapper.selectRouteByRoleId(roleId);
        List<String> routeIds = routePOList.stream().map(RoutePO::getId).collect(Collectors.toList());
        return new RoleRightTreeDTO(tree, routeIds, roleId);
    }
}

